home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Graphics Programming (2nd Edition) / Visual Basic Graphics Programming 2nd Edition.iso / Src / Ch16 / Solid.cls < prev    next >
Text File  |  1999-06-26  |  8KB  |  332 lines

  1. VERSION 1.0 CLASS
  2. BEGIN
  3.   MultiUse = -1  'True
  4.   Persistable = 0  'NotPersistable
  5.   DataBindingBehavior = 0  'vbNone
  6.   DataSourceBehavior  = 0  'vbNone
  7.   MTSTransactionMode  = 0  'NotAnMTSObject
  8. END
  9. Attribute VB_Name = "Solid3d"
  10. Attribute VB_GlobalNameSpace = False
  11. Attribute VB_Creatable = False
  12. Attribute VB_PredeclaredId = False
  13. Attribute VB_Exposed = False
  14. Option Explicit
  15.  
  16. ' These Face3d objects are the oriented faces.
  17. Public Faces As Collection
  18.  
  19. Public zmax As Single
  20.  
  21. Public IsConvex As Boolean
  22. Public HideSurfaces As Boolean
  23. ' Set the diffuse reflection coefficients for
  24. ' the faces.
  25. Public Sub SetDiffuseCoefficients(ByVal kr As Single, ByVal kg As Single, ByVal kb As Single)
  26. Dim face As Face3d
  27.  
  28.     For Each face In Faces
  29.         face.DiffuseKr = kr
  30.         face.DiffuseKg = kg
  31.         face.DiffuseKb = kb
  32.     Next face
  33. End Sub
  34.  
  35.  
  36. ' Sort the faces so those with the largest
  37. ' transformed Z coordinates come first.
  38. '
  39. ' As we switch faces around, we keep track of the
  40. ' number of switches we have made. If it clear we
  41. ' are stuck in an infinite loop, just move the
  42. ' first face to the ordered_faces collection so we
  43. ' can continue.
  44. Public Sub SortFaces()
  45. Dim ordered_faces As Collection
  46. Dim face_1 As Face3d
  47. Dim face_i As Face3d
  48. Dim i As Integer
  49. Dim Xmin As Single
  50. Dim xmax As Single
  51. Dim ymin As Single
  52. Dim ymax As Single
  53. Dim zmin As Single
  54. Dim zmax As Single
  55. Dim xmini As Single
  56. Dim xmaxi As Single
  57. Dim ymini As Single
  58. Dim ymaxi As Single
  59. Dim zmini As Single
  60. Dim zmaxi As Single
  61. Dim overlap As Boolean
  62. Dim switches As Integer
  63. Dim max_switches As Integer
  64.  
  65.     Set ordered_faces = New Collection
  66.  
  67.     ' Pull out any that are culled. These are not
  68.     ' drawn so we can put them at the front of
  69.     ' the ordered_faces collection.
  70.     For i = Faces.Count To 1 Step -1
  71.         If Faces(i).IsCulled Then
  72.             ordered_faces.Add Faces(i)
  73.             Faces.Remove i
  74.         End If
  75.     Next i
  76.  
  77.     ' Order the remaining faces.
  78.     max_switches = Faces.Count
  79.     Do While Faces.Count > 0
  80.         ' Get the first item's extent.
  81.         Set face_1 = Faces(1)
  82.         face_1.GetExtent Xmin, xmax, ymin, ymax, zmin, zmax
  83.  
  84.         ' Compare this face to the others.
  85.         overlap = False     ' In case Face.Count = 0.
  86.         For i = 2 To Faces.Count
  87.             Set face_i = Faces(i)
  88.  
  89.             ' Get item i's extent.
  90.             face_i.GetExtent xmini, xmaxi, ymini, ymaxi, zmini, zmaxi
  91.             overlap = True
  92.             If xmaxi <= Xmin Or xmini >= xmax Or _
  93.                ymaxi <= ymin Or ymini >= ymax Or _
  94.                zmini >= zmax _
  95.             Then
  96.                 ' The extents do not overlap.
  97.                 overlap = False
  98.             ElseIf face_i.IsAbove(face_1) Then
  99.                 ' Face i is all above the plane
  100.                 ' of face 1.
  101.                 overlap = False
  102.             ElseIf face_1.IsBelow(face_i) Then
  103.                 ' Face 1 is all beneath the plane
  104.                 ' of face i.
  105.                 overlap = False
  106.             ElseIf Not face_1.Obscures(face_i) Then
  107.                 ' If face_1 does not lie partly above
  108.                 ' face_i, then there is no problem.
  109.                 overlap = False
  110.             End If
  111.  
  112.             If overlap Then Exit For
  113.         Next i
  114.  
  115.         If overlap And switches < max_switches Then
  116.             ' There's overlap, move face i to the
  117.             ' top of the list.
  118.             Faces.Remove i
  119.             Faces.Add face_i, , 1 ' Before position 1.
  120.             switches = switches + 1
  121.         Else
  122.             ' There's no overlap. Move face 1 to
  123.             ' the ordered_faces collection.
  124.             ordered_faces.Add face_1
  125.             Faces.Remove 1
  126.             max_switches = Faces.Count
  127.             switches = 0
  128.         End If
  129.     Loop ' Loop until we've ordered all the faces.
  130.  
  131.     ' Replace the Faces collection with the
  132.     ' ordered_faces collection.
  133.     Set Faces = ordered_faces
  134. End Sub
  135. ' Set the ZMax value for the solid.
  136. Public Sub SetZmax()
  137. Dim face As Face3d
  138. Dim z_max As Single
  139.  
  140.     zmax = -1E+30
  141.  
  142.     For Each face In Faces
  143.         z_max = face.zmax()
  144.         If zmax < z_max Then zmax = z_max
  145.     Next face
  146. End Sub
  147. ' Create a pyramid with height L and base given
  148. ' by the points in the coord array. Add the
  149. ' faces that make up the pyramid to this solid.
  150. Public Sub Stellate(L As Single, ParamArray coord() As Variant)
  151. Dim x0 As Single
  152. Dim y0 As Single
  153. Dim z0 As Single
  154. Dim x1 As Single
  155. Dim y1 As Single
  156. Dim z1 As Single
  157. Dim x2 As Single
  158. Dim y2 As Single
  159. Dim z2 As Single
  160. Dim x3 As Single
  161. Dim y3 As Single
  162. Dim z3 As Single
  163. Dim Ax As Single
  164. Dim Ay As Single
  165. Dim Az As Single
  166. Dim Bx As Single
  167. Dim By As Single
  168. Dim Bz As Single
  169. Dim Nx As Single
  170. Dim Ny As Single
  171. Dim Nz As Single
  172. Dim num As Integer
  173. Dim i As Integer
  174. Dim pt As Integer
  175.  
  176.     num = (UBound(coord) + 1) \ 3
  177.     If num < 3 Then
  178.         MsgBox "Must have at least 3 points to stellate.", , vbExclamation
  179.         Exit Sub
  180.     End If
  181.  
  182.     ' (x0, y0, z0) is the center of the polygon.
  183.     x0 = 0
  184.     y0 = 0
  185.     z0 = 0
  186.     pt = 0
  187.     For i = 1 To num
  188.         x0 = x0 + coord(pt)
  189.         y0 = y0 + coord(pt + 1)
  190.         z0 = z0 + coord(pt + 2)
  191.         pt = pt + 3
  192.     Next i
  193.     x0 = x0 / num
  194.     y0 = y0 / num
  195.     z0 = z0 / num
  196.  
  197.     ' Find the normal.
  198.     x1 = coord(0)
  199.     y1 = coord(1)
  200.     z1 = coord(2)
  201.     x2 = coord(3)
  202.     y2 = coord(4)
  203.     z2 = coord(5)
  204.     x3 = coord(6)
  205.     y3 = coord(7)
  206.     z3 = coord(8)
  207.     Ax = x2 - x1
  208.     Ay = y2 - y1
  209.     Az = z2 - z1
  210.     Bx = x3 - x2
  211.     By = y3 - y2
  212.     Bz = z3 - z2
  213.     m3Cross Nx, Ny, Nz, Ax, Ay, Az, Bx, By, Bz
  214.  
  215.     ' Give the normal length L.
  216.     m3SizeVector L, Nx, Ny, Nz
  217.  
  218.     ' The normal + <x0, y0, z0> gives the point.
  219.     x0 = x0 + Nx
  220.     y0 = y0 + Ny
  221.     z0 = z0 + Nz
  222.  
  223.     ' Build the faces.
  224.     x1 = coord(3 * num - 3)
  225.     y1 = coord(3 * num - 2)
  226.     z1 = coord(3 * num - 1)
  227.     pt = 0
  228.     For i = 1 To num
  229.         x2 = coord(pt)
  230.         y2 = coord(pt + 1)
  231.         z2 = coord(pt + 2)
  232.         AddFace x1, y1, z1, x2, y2, z2, x0, y0, z0
  233.         x1 = x2
  234.         y1 = y2
  235.         z1 = z2
  236.         pt = pt + 3
  237.     Next i
  238. End Sub
  239.  
  240.  
  241. ' Clip faces.
  242. Public Sub ClipEye(ByVal R As Single)
  243. Dim obj As Face3d
  244.  
  245.     For Each obj In Faces
  246.         obj.ClipEye R
  247.     Next obj
  248. End Sub
  249.  
  250. ' Add an oriented face to the solid.
  251. Public Sub AddFace(ParamArray coord() As Variant)
  252. Dim face As Face3d
  253. Dim num As Integer
  254. Dim pt As Integer
  255. Dim i As Integer
  256.  
  257.     num = (UBound(coord) + 1) \ 3
  258.     If num < 3 Then
  259.         MsgBox "Faces in a Solid must contain at least 3 points.", , vbExclamation
  260.         Exit Sub
  261.     End If
  262.  
  263.     Set face = New Face3d
  264.     Faces.Add face
  265.  
  266.     pt = 0
  267.     For i = 1 To num
  268.         face.AddPoints (coord(pt)), (coord(pt + 1)), (coord(pt + 2))
  269.         pt = pt + 3
  270.     Next i
  271. End Sub
  272. ' Perform backface removal on the faces for
  273. ' center of projection at (X, Y, Z).
  274. Public Sub Cull(ByVal X As Single, ByVal Y As Single, ByVal Z As Single)
  275. Dim obj As Face3d
  276.  
  277.     For Each obj In Faces
  278.         obj.Cull X, Y, Z
  279.     Next obj
  280. End Sub
  281. ' Set or clear the Culled property for all faces.
  282. Property Let Culled(ByVal new_value As Boolean)
  283. Dim obj As Face3d
  284.  
  285.     For Each obj In Faces
  286.         obj.IsCulled = new_value
  287.     Next obj
  288. End Property
  289.  
  290.  
  291.  
  292. ' Apply a transformation matrix which may not
  293. ' contain 0, 0, 0, 1 in the last column to the
  294. ' object.
  295. Public Sub ApplyFull(M() As Single)
  296. Dim obj As Face3d
  297.  
  298.     For Each obj In Faces
  299.         obj.ApplyFull M
  300.     Next obj
  301. End Sub
  302.  
  303. ' Apply a transformation matrix to the object.
  304. Public Sub Apply(M() As Single)
  305. Dim obj As Face3d
  306.  
  307.     For Each obj In Faces
  308.         obj.Apply M
  309.     Next obj
  310. End Sub
  311.  
  312.  
  313. ' Draw the transformed solid on a PictureBox.
  314. Public Sub Draw(ByVal pic As PictureBox, ByVal light_sources As Collection)
  315. Dim face As Face3d
  316.  
  317.     ' If we do not know this is a convex solid,
  318.     ' order the faces.
  319.     If HideSurfaces And (Not IsConvex) Then SortFaces
  320.  
  321.     ' Draw the faces.
  322.     For Each face In Faces
  323.         face.Draw pic, light_sources
  324.     Next face
  325. End Sub
  326.  
  327. Private Sub Class_Initialize()
  328.     Set Faces = New Collection
  329. End Sub
  330.  
  331.  
  332.